// Decompiled by DJ v3.10.10.93 Copyright 2007 Atanas Neshkov  Date: 27/11/2008 22:57:26
// Home Page: http://members.fortunecity.com/neshkov/dj.html  http://www.neshkov.com/dj.html - Check often for new version!
// Decompiler options: packimports(3) 
// Source File Name:   GameState.java

package reversi;

import java.awt.Rectangle;
import java.util.Vector;

// Referenced classes of package reversi:
//            Move

public class GameState
{

    public GameState()
    {
        this(8);
    }

    public GameState(int i)
    {
        gridWidth = i;
        width = i + 3 >> 2;
        height = i;
        reset();
    }

    public GameState(GameState gamestate)
    {
        width = gamestate.width;
        height = gamestate.height;
        gridWidth = gamestate.gridWidth;
        data = new byte[width * height];
        System.arraycopy(gamestate.data, 0, data, 0, data.length);
        minX = gamestate.minX;
        minY = gamestate.minY;
        maxX = gamestate.maxX;
        maxY = gamestate.maxY;
    }

    public void reset()
    {
        data = new byte[width * height];
        minX = gridWidth;
        minY = height;
        maxX = maxY = 0;
        int i = height / 2;
        setValueAt(i - 1, i - 1, 1);
        setValueAt(i - 1, i, 2);
        setValueAt(i, i - 1, 2);
        setValueAt(i, i, 1);
        minX = minY = i - 1;
        maxX = maxY = i;
    }

    public int getWidth()
    {
        return gridWidth;
    }

    public int getHeight()
    {
        return height;
    }

    public int getMarkAt(int i, int j)
    {
        int k = i >> 2;
        int l = (i & 3) << 1;
        return (data[j * width + k] >> l & 3) - 1;
    }

    public boolean addMove(Move move)
    {
        return setMarkAt(move.x, move.y, move.player);
    }

    public boolean setMarkAt(int i, int j, int k)
    {
        if(getValueAt(i, j) != 0 || i < 0 || i >= gridWidth || j < 0 || j >= height)
            return false;
        if(i < minX)
            minX = i;
        if(j < minY)
            minY = j;
        if(i > maxX)
            maxX = i;
        if(j > maxY)
            maxY = j;
        boolean flag = false;
        for(int l = 0; l < directions.length; l++)
        {
            int i1 = directions[l][0];
            int j1 = directions[l][1];
            int k1 = i;
            int l1 = j;
            int i2 = k;
            int j2 = 0;
            do
            {
                k1 += i1;
                l1 += j1;
                if(k1 < 0 || l1 < 0 || k1 >= gridWidth || l1 >= height)
                    break;
                i2 = getValueAt(k1, l1) - 1;
                j2++;
            } while(i2 == 1 - k);
            if(i2 != k || j2 <= 1)
                continue;
            flag = true;
            k1 = i;
            l1 = j;
            for(int k2 = 0; k2 < j2; k2++)
            {
                k1 += i1;
                l1 += j1;
                setValueAt(k1, l1, k + 1);
            }

        }

        if(!flag)
        {
            return false;
        } else
        {
            setValueAt(i, j, k + 1);
            return true;
        }
    }

    public Vector getPossibleMoves(int i)
    {
        boolean flag = false;
        Rectangle rectangle = getInterestingArea();
        Vector vector = new Vector();
        for(int j = rectangle.x; j < rectangle.x + rectangle.width; j++)
        {
            for(int k = rectangle.y; k < rectangle.y + rectangle.height; k++)
                if(isPossibleMove(j, k, i))
                    vector.addElement(new Move(j, k, i));

        }

        return vector;
    }

    public int getPossibleMoveCount(int i)
    {
        Rectangle rectangle = getInterestingArea();
        int j = 0;
        for(int k = rectangle.x; k < rectangle.x + rectangle.width; k++)
        {
            for(int l = rectangle.y; l < rectangle.y + rectangle.height; l++)
                if(isPossibleMove(k, l, i))
                    j++;

        }

        return j;
    }

    public boolean isPossibleMove(int i, int j, int k)
    {
        if(getMarkAt(i, j) != -1)
            return false;
        for(int l = 0; l < directions.length; l++)
        {
            int i1 = directions[l][0];
            int j1 = directions[l][1];
            int k1 = i;
            int l1 = j;
            int i2 = k;
            int j2 = 0;
            do
            {
                k1 += i1;
                l1 += j1;
                if(k1 < 0 || l1 < 0 || k1 >= gridWidth || l1 >= height)
                    break;
                i2 = getValueAt(k1, l1) - 1;
                j2++;
            } while(i2 == 1 - k);
            if(i2 == k && j2 > 1)
                return true;
        }

        return false;
    }

    public int getMarkCount(int i)
    {
        int j = 0;
        for(int k = 0; k < gridWidth; k++)
        {
            for(int l = 0; l < height; l++)
                if(getMarkAt(k, l) == i)
                    j++;

        }

        return j;
    }

    public Rectangle getInterestingArea()
    {
        int i = Math.min(maxX + 1, gridWidth - 1);
        int j = Math.min(maxY + 1, height - 1);
        int k = Math.max(0, minX - 1);
        int l = Math.max(0, minY - 1);
        return new Rectangle(k, l, (i - k) + 1, (j - l) + 1);
    }

    public GameState getNewInstance(Move move)
    {
        if(move != null)
            return getNewInstance(move.x, move.y, move.player);
        else
            return this;
    }

    public GameState getNewInstance(int i, int j, int k)
    {
        GameState gamestate = new GameState(this);
        if(!gamestate.setMarkAt(i, j, k))
            return null;
        else
            return gamestate;
    }

    int getValueAt(int i, int j)
    {
        return data[j * width + (i >> 2)] >> ((i & 3) << 1) & 3;
    }

    void setValueAt(int i, int j, int k)
    {
        int l = i >> 2;
        int i1 = (i & 3) << 1;
        int j1 = j * width + l;
        data[j1] &= ~(3 << i1);
        data[j1] |= k << i1;
    }

    public boolean equals(Object obj)
    {
        return equals((GameState)obj);
    }

    public boolean equals(GameState gamestate)
    {
        if(gamestate.gridWidth != gridWidth || gamestate.height != height || gamestate.minX != minX || gamestate.minY != minY || gamestate.maxX != maxX || gamestate.maxY != maxY)
            return false;
        for(int i = 0; i < data.length; i++)
            if(gamestate.data[i] != data[i])
                return false;

        return true;
    }

    void reorder()
    {
        int i = getMarkCount(0);
        int j = getMarkCount(1);
        int k = 0;
        int l = 0;
        for(; k < gridWidth; k++)
        {
            for(int i1 = 0; i1 < height;)
            {
                byte byte0 = -1;
                if(l < i)
                    byte0 = 0;
                else
                if(l < i + j)
                    byte0 = 1;
                setValueAt(k, i1, byte0 + 1);
                i1++;
                l++;
            }

        }

    }

    public String toString()
    {
        StringBuffer stringbuffer = new StringBuffer();
        for(int i = 0; i < height; i++)
        {
            for(int j = 0; j < gridWidth; j++)
                switch(getValueAt(j, i))
                {
                case 0: // '\0'
                    stringbuffer.append(' ');
                    break;

                case 1: // '\001'
                    stringbuffer.append('o');
                    break;

                case 2: // '\002'
                    stringbuffer.append('x');
                    break;
                }

            stringbuffer.append('\n');
        }

        return stringbuffer.toString();
    }

    byte data[];
    int gridWidth;
    int width;
    int height;
    int minX;
    int minY;
    int maxX;
    int maxY;
    private static final int directions[][] = {
        {
            -1, -1
        }, {
            0, -1
        }, {
            1, -1
        }, {
            -1, 0
        }, {
            1, 0
        }, {
            -1, 1
        }, {
            0, 1
        }, {
            1, 1
        }
    };

}